package org.example;

import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Goal which count your files in the build.其中预绑定周期为validate.预调用为mvn process-classes
 *
 * @version $Id$
 * @phase validate
 * @execute phase="process-classes"
 * @goal count
 * @threadSafe
 * @since 2.0
 */
public class CountMojo extends AbstractMojo {

    private static final String[] INCLUDES_DEFAULT = {"java", "xml", "properties"};

    /**
     * @parameter expression = "${project.basedir}"
     * @required
     * @readonly
     */
    private File basedir;

    /**
     * @parameter expression = "${project.build.sourceDirectory}"
     * @required
     * @readonly
     */
    private File sourceDirectory;

    /**
     * @parameter expression = "${project.build.testSourceDirectory}"
     * @required
     * @readonly
     */
    private File testSourceDirectory;

    /**
     * @parameter expression = "${project.build.resources}"
     * @required
     * @readonly
     */
    private List<Resource> resources;

    /**
     * @parameter expression = "${project.build.testResources}"
     * @required
     * @readonly
     */
    private List<Resource> testResources;

    /**
     * The file types which will included for counting
     *
     * @parameter
     */
    private String[] includes;

    {
        System.out.println("CountMojo类中的构造代码块执行");
    }

    static {
        System.out.println("CountMojo类中的静态代码块执行了");
    }

    public CountMojo() {
        System.out.println("CountMojo类中的无参构造方法执行了");
    }

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {


        System.out.println("CountMojo类中的execute方法执行了");
        System.out.println("CountMojo类中获取到basedir="+basedir.getAbsolutePath());


        if (includes == null || includes.length == 0) {
            includes = INCLUDES_DEFAULT;
        }

        for (String s : includes
        ) {
            System.out.println("CountMojo类中获取到include="+s);
        }


        try {
            countDir(sourceDirectory);
            countDir(testSourceDirectory);

            for (Resource resource : resources
            ) {
                countDir(new File(resource.getDirectory()));
            }

            for (Resource resource : testResources
            ) {
                countDir(new File(resource.getDirectory()));
            }
        } catch (IOException e) {
            throw new MojoExecutionException("Unable to count lines of code.", e);
        }
    }

    private void countDir(File dir) throws IOException {

        if (!dir.exists()) {
            return;
        }

        List<File> collected = new ArrayList<File>();

        collectFiles(collected, dir);

        int lines = 0;

        for (File sourceFile : collected
        ) {
            lines += countLine(sourceFile);
        }

        String path = dir.getAbsolutePath().substring(basedir.getAbsolutePath().length());

        getLog().info(path + ":" + lines + " lines of code in  " + collected.size() + " files");
    }

    private void collectFiles(List<File> collected, File file) {
        if (file.isFile()) {
            for (String include : includes
            ) {
                if (file.getName().endsWith("." + include)) {
                    collected.add(file);
                    break;
                }
            }
        } else {
            for (File sub : file.listFiles()
            ) {
                collectFiles(collected, sub);
            }
        }
    }

    private int countLine(File file) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(file));

        int line = 0;

        try {
            while (reader.ready()) {
                reader.readLine();
                line++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            reader.close();
        }

        return line;
    }
}
